#include "preHeader.h"
#include "LuaGame.h"
#include "LuaHookEvent.h"
#include "Map/MapInstance.h"
#include "Spell/SpellMgr.h"
#include "Spell/SpellEffects.h"
#include "Session/GameServerMgr.h"
#include "timer/WheelTimer.h"

static void InitLuaBase(lua_State* L)
{
	lua::dofile(L, "scripts/Init.lua");
	lua::dofile(L, "scripts/Effect/Init.lua");
	lua::dofile(L, "scripts/AI/Init.lua");
	lua::dofile(L, "scripts/AI/AINodeBase.lua");
	lua::dofile(L, "scripts/AI/AISampleNode.lua");
	lua::dofile(L, "scripts/protocol/OpCode.lua");
	lua::dofile(L, "scripts/protocol/InternalProtocol.lua");
	lua::dofile(L, "scripts/NetBuffer.lua");
	AIActor::InitBehaviorTree(L);
	LocatableObject::InitBlackboard(L);
	lua::class_add<WheelRoutineType>(L, "WheelRoutineType");
	lua::class_def<WheelRoutineType>(L, "NewUniqueRoutineType", &WheelRoutineType::NewUniqueRoutineType);
	lua::class_add<WheelTimerOwner>(L, "WheelTimerOwner");
	lua::class_def<WheelTimerOwner>(L, "CreateTimer", &WheelTimerOwner::CreateTimer);
	lua::class_def<WheelTimerOwner>(L, "CreateTimerX", &WheelTimerOwner::CreateTimerX);
	lua::class_def<WheelTimerOwner>(L, "RemoveTimers", (void(WheelTimerOwner::*)(uint32))&WheelTimerOwner::RemoveTimers);
	lua::class_def<WheelTimerOwner>(L, "FindTimer", &WheelTimerOwner::FindTimer<WheelTimer>);
	lua::class_add<WheelTimer>(L, "WheelTimer");
	lua::class_def<WheelTimer>(L, "RePush", &WheelTimer::RePush);
	lua::class_def<WheelTimer>(L, "GetRemainder", &WheelTimer::GetRemainder);
	lua::def(L, "unixtime", System::GetUnixTime);
	lua::def(L, "systime", System::GetSysTime);
	lua::def(L, "DoScriptFile", DoScriptFile);
	lua::def(L, "DoScriptFileById", DoScriptFileById);
	lua::def(L, "CastCallable", CastCallable);
	lua::def(L, "CastCallableWithDtor", CastCallableWithDtor);
}

static void InitLuaAttribute(lua_State* L)
{
	LuaTable t(L, "ATTRARITHTYPE");
	t.set("BASE", ATTRARITHTYPE::BASE);
	t.set("SCALE", ATTRARITHTYPE::SCALE);
	t.set("FINAL", ATTRARITHTYPE::FINAL);

	t.reset(L, "ATTRPARTTYPE");
	t.set("BASE", ATTRPARTTYPE::BASE);
	t.set("BODY", ATTRPARTTYPE::BODY);
	t.set("EQUIP", ATTRPARTTYPE::EQUIP);
	t.set("BUFF", ATTRPARTTYPE::BUFF);

	t.reset(L, "ATTRTYPE");
	t.set("HIT_POINT", ATTRTYPE::HIT_POINT);
	t.set("MAGIC_POINT", ATTRTYPE::MAGIC_POINT);
	t.set("ATTACK_VALUE", ATTRTYPE::ATTACK_VALUE);
	t.set("DEFENSE_VALUE", ATTRTYPE::DEFENSE_VALUE);
	t.set("HIT_CHANCE", ATTRTYPE::HIT_CHANCE);
	t.set("DODGE_CHANCE", ATTRTYPE::DODGE_CHANCE);
	t.set("CRITIHIT_CHANCE", ATTRTYPE::CRITIHIT_CHANCE);
	t.set("CRITIHIT_CHANCE_RESIST", ATTRTYPE::CRITIHIT_CHANCE_RESIST);
	t.set("CRITIHIT_INTENSITY", ATTRTYPE::CRITIHIT_INTENSITY);
	t.set("CRITIHIT_INTENSITY_RESIST", ATTRTYPE::CRITIHIT_INTENSITY_RESIST);

	t.reset(L, "ATTREXTYPE");
	t.set("CANT_LOSE_HP", ATTREXTYPE::CANT_LOSE_HP);
	t.set("CANT_DEAD", ATTREXTYPE::CANT_DEAD);

	t.reset(L, "ATTRVEXTYPE");

	t.reset(L, "ATTRSEXTYPE");

	t.reset(L, "AURA_STATE");
	t.set("INVINCIBLE", AURA_STATE_INVINCIBLE);
	t.set("INVISIBLE", AURA_STATE_INVISIBLE);
	t.set("FETTER", AURA_STATE_FETTER);
	t.set("STUN", AURA_STATE_STUN);

	lua::class_add<Attribute>(L, "Attribute");
	lua::class_def<Attribute>(L, "ModAttr", &Attribute::ModAttr);
	lua::class_def<Attribute>(L, "ModXAttr", &Attribute::ModXAttr);
	lua::class_def<Attribute>(L, "GetAttr", &Attribute::GetAttr);
	lua::class_def<Attribute>(L, "ModAttrEx", &Attribute::ModAttrEx);
	lua::class_def<Attribute>(L, "GetAttrEx", &Attribute::GetAttrEx);
	lua::class_def<Attribute>(L, "AttachAttrVex", &Attribute::AttachAttrVex);
	lua::class_def<Attribute>(L, "DetachAttrVex", &Attribute::DetachAttrVex);
	lua::class_def<Attribute>(L, "AttachAttrSex", &Attribute::AttachAttrSex);
	lua::class_def<Attribute>(L, "DetachAttrSex", &Attribute::DetachAttrSex);
	lua::class_def<Attribute>(L, "CalcAttackDamage", &Attribute::CalcAttackDamage);
}

static void InitLuaVariable(lua_State* L)
{
	lua::set<LuaTable&&>(L, "gSpellEffectArgs", LuaTable(L));
	lua::set(L, "emptyString", &emptyString);
	lua::set(L, "emptyStringView", &emptyStringView);
	lua::set(L, "vector3f_INVALID", &vector3f_INVALID);
	lua::set(L, "vector3f_NULL", &vector3f_NULL);
	lua::set(L, "vector3f1f_NULL", &vector3f1f_NULL);
	lua::set(L, "vector3f3f_NULL", &vector3f3f_NULL);

	lua::set(L, "CommonSuccess", CommonSuccess);

	lua::set(L, "SendPacket2GS",
		CastScriptCallable<void(uint32, uint32, const std::string_view&)>(
			[](uint32 gsIdx, uint32 opcode, const std::string_view& data) {
				NetPacket wrapper(opcode);
				const INetPacket* pcks[] = { &wrapper };
				const std::string_view datas[] = { data };
				GSSession(gsIdx).PushSendPacket(pcks, 1, datas, 1);
			}));
}

static void InitLuaItem(lua_State* L)
{
	LuaTable t(L, "ItemSlotType");
	t.set("Equip", ItemSlotEquipType);
	t.set("Bag", ItemSlotBagType);
	t.set("Bank", ItemSlotBankType);

	lua::set(L, "ItemSlotInvalid", ItemSlotInvalid);

	lua::class_add<ItemStorage>(L, "ItemStorage");
	lua::class_def<ItemStorage>(L, "GetOwner", &ItemStorage::GetOwner);
	lua::class_def<ItemStorage>(L, "GetItem", &ItemStorage::GetItem);
	lua::class_def<ItemStorage>(L, "CreateAddItem", &ItemStorage::CreateAddItem);
	lua::class_def<ItemStorage>(L, "GetFillItemLackSlotCount", &ItemStorage::GetFillItemLackSlotCount);
	lua::class_def<ItemStorage>(L, "CreateAddItems", &ItemStorage::CreateAddItems);
	lua::class_def<ItemStorage>(L, "GetFillItemsLackSlotCount", &ItemStorage::GetFillItemsLackSlotCount);
	lua::class_def<ItemStorage>(L, "EquipItem", &ItemStorage::EquipItem);
	lua::class_def<ItemStorage>(L, "UnequipItem", &ItemStorage::UnequipItem);

	lua::class_add<Item>(L, "Item");
	lua::class_def<Item>(L, "GetOwner", &Item::GetOwner);
	lua::class_def<Item>(L, "GetItemTypeID", &Item::GetItemTypeID);
	lua::class_def<Item>(L, "GetItemCount", &Item::GetItemCount);
}

static void InitLuaQuest(lua_State* L)
{
	LuaTable t(L, "QuestWhenType");
	t.set("Accept", QuestWhenType::Accept);
	t.set("Finish", QuestWhenType::Finish);
	t.set("Failed", QuestWhenType::Failed);
	t.set("Cancel", QuestWhenType::Cancel);
	t.set("Submit", QuestWhenType::Submit);

	lua::class_add<QuestPrototype::Flags>(L, "QuestPrototype::Flags");
	lua::class_mem<QuestPrototype::Flags>(L, "isStoryMode", &QuestPrototype::Flags::isStoryMode);
	lua::class_mem<QuestPrototype::Flags>(L, "isEnterSceneAeap", &QuestPrototype::Flags::isEnterSceneAeap);
	lua::class_mem<QuestPrototype::Flags>(L, "isLeaveSceneAeap", &QuestPrototype::Flags::isLeaveSceneAeap);

	lua::class_add<QuestStorage>(L, "QuestStorage");
	lua::class_def<QuestStorage>(L, "SetQuestFinished", &QuestStorage::SetQuestFinished);

	lua::class_add<QuestLog>(L, "QuestLog");
	lua::class_def<QuestLog>(L, "GetOwner", &QuestLog::GetOwner);
	lua::class_def<QuestLog>(L, "GetQuestGuid", &QuestLog::GetQuestGuid);
	lua::class_def<QuestLog>(L, "GetQuestTypeID", &QuestLog::GetQuestTypeID);
	lua::class_def<QuestLog>(L, "GetQuestFlags", &QuestLog::GetQuestFlags);
	lua::class_def<QuestLog>(L, "Failed", &QuestLog::Failed);
}

static void InitLuaSpell(lua_State* L)
{
	LuaTable t(L, "CanCastSpellFlag");
	t.set("CheckDistance", CanCastSpellFlag::CheckDistance);

	lua::class_add<Spell>(L, "Spell");
	lua::class_def<Spell>(L, "SaveEffectTable", &Spell::SaveEffectTable);
	lua::class_def<Spell>(L, "SaveEffectInstInfos", &Spell::SaveEffectInstInfos);
	lua::class_def<Spell>(L, "SaveEffectBuffInfos", &Spell::SaveEffectBuffInfos);

	lua::class_add<SpellEffects>(L, "SpellEffects");
	lua::class_def<SpellEffects>(L, "Apply4Mine", &SpellEffects::Apply4Mine);
}

static void InitLuaObject(lua_State* L)
{
	lua::set(L, "TYPE_OBJECT", TYPE_OBJECT);
	lua::set(L, "TYPE_LOCATABLEOBJECT", TYPE_LOCATABLEOBJECT);
	lua::set(L, "TYPE_STATICOBJECT", TYPE_STATICOBJECT);
	lua::set(L, "TYPE_AURAOBJECT", TYPE_AURAOBJECT);
	lua::set(L, "TYPE_UNIT", TYPE_UNIT);
	lua::set(L, "TYPE_CREATURE", TYPE_CREATURE);
	lua::set(L, "TYPE_PLAYER", TYPE_PLAYER);
	lua::set(L, "TYPE_AUTOPLAYER", TYPE_AUTOPLAYER);

	lua::set(L, "UNIT64_FIELD_HP", UNIT64_FIELD_HP);
	lua::set(L, "UNIT64_FIELD_HP_MAX", UNIT64_FIELD_HP_MAX);

	LuaTable t(L, "ObjectHookEvent");
	t.set("OnSObjUnitEnter", ObjectHookEvent::OnSObjUnitEnter);
	t.set("OnSObjUnitLeave", ObjectHookEvent::OnSObjUnitLeave);
	t.set("OnEObjUnitEnter", ObjectHookEvent::OnEObjUnitEnter);
	t.set("OnEObjUnitLeave", ObjectHookEvent::OnEObjUnitLeave);
	t.set("OnUnitChangeCombatStatus", ObjectHookEvent::OnUnitChangeCombatStatus);
	t.set("OnUnitHurted", ObjectHookEvent::OnUnitHurted);
	t.set("OnUnitKilled", ObjectHookEvent::OnUnitKilled);
	t.set("OnUnitDead", ObjectHookEvent::OnUnitDead);
	t.set("OnPlayerChangeTeam", ObjectHookEvent::OnPlayerChangeTeam);
	t.set("OnPlayerChangeGuild", ObjectHookEvent::OnPlayerChangeGuild);
	t.set("OnPlayerChangeQuestStatus", ObjectHookEvent::OnPlayerChangeQuestStatus);
	t.set("OnPlayerDelete", ObjectHookEvent::OnPlayerDelete);
	t.set("OnSendMessage", ObjectHookEvent::OnSendMessage);
	t.set("OnHookDetach", ObjectHookEvent::OnHookDetach);

	lua::class_add<Object>(L, "Object");
	lua::class_inh<Object, AIActor>(L);
	lua::class_def<Object>(L, "SetS32Value", &Object::SetS32Value);
	lua::class_def<Object>(L, "SetF32Value", &Object::SetF32Value);
	lua::class_def<Object>(L, "ModS32Value", &Object::ModS32Value);
	lua::class_def<Object>(L, "ModF32Value", &Object::ModF32Value);
	lua::class_def<Object>(L, "SetS64Value", &Object::SetS64Value);
	lua::class_def<Object>(L, "SetF64Value", &Object::SetF64Value);
	lua::class_def<Object>(L, "ModS64Value", &Object::ModS64Value);
	lua::class_def<Object>(L, "ModF64Value", &Object::ModF64Value);
	lua::class_def<Object>(L, "SetFlag", &Object::SetFlag);
	lua::class_def<Object>(L, "RemoveFlag", &Object::RemoveFlag);
	lua::class_def<Object>(L, "HasFlag", &Object::HasFlag);
	lua::class_def<Object>(L, "HasOneOfFlag", &Object::HasOneOfFlag);
	lua::class_def<Object>(L, "GetS32Value", &Object::GetS32Value);
	lua::class_def<Object>(L, "GetF32Value", &Object::GetF32Value);
	lua::class_def<Object>(L, "GetS64Value", &Object::GetS64Value);
	lua::class_def<Object>(L, "GetF64Value", &Object::GetF64Value);
	lua::class_def<Object>(L, "GetGuid", &Object::GetGuid);
	lua::class_def<Object>(L, "GetGuidLow", &Object::GetGuidLow);
	lua::class_def<Object>(L, "GetObjectType", &Object::GetObjectType);
	lua::class_def<Object>(L, "IsType", &Object::IsType);
	lua::class_def<Object>(L, "IsKindOf", &Object::IsKindOf);

	lua::class_add<LocatableObject>(L, "LocatableObject");
	lua::class_inh<LocatableObject, Object>(L);
	lua::class_cast<LocatableObject, WheelRoutineType>(L);
	lua::class_cast<LocatableObject, WheelTimerOwner>(L);
	lua::class_def<LocatableObject>(L, "SetPosition", &LocatableObject::SetPosition);
	lua::class_def<LocatableObject>(L, "SetDirection", &LocatableObject::SetDirection);
	lua::class_def<LocatableObject>(L, "SetOrientation", &LocatableObject::SetOrientation);
	lua::class_def<LocatableObject>(L, "Relocate",
		(void(LocatableObject::*)(const vector3f&))&LocatableObject::Relocate);
	lua::class_def<LocatableObject>(L, "RelocateWithDirection",
		(void(LocatableObject::*)(const vector3f&, const vector3f&))&LocatableObject::Relocate);
	lua::class_def<LocatableObject>(L, "RelocateWithOrientation",
		(void(LocatableObject::*)(const vector3f&, float))&LocatableObject::Relocate);
	lua::class_def<LocatableObject>(L, "PushMessage", &LocatableObject::PushMessage);
	lua::class_def<LocatableObject>(L, "SendMessageToSet", &LocatableObject::SendMessageToSet);
	lua::class_def<LocatableObject>(L, "GetDistance",
		(float(LocatableObject::*)(const vector3f&) const)&LocatableObject::GetDistance);
	lua::class_def<LocatableObject>(L, "GetDistance2D",
		(float(LocatableObject::*)(const vector3f&) const)&LocatableObject::GetDistance2D);
	lua::class_def<LocatableObject>(L, "GetDistanceSq",
		(float(LocatableObject::*)(const vector3f&) const)&LocatableObject::GetDistanceSq);
	lua::class_def<LocatableObject>(L, "GetDistance2DSq",
		(float(LocatableObject::*)(const vector3f&) const)&LocatableObject::GetDistance2DSq);
	lua::class_def<LocatableObject>(L, "GetDistance2obj",
		(float(LocatableObject::*)(const LocatableObject*) const)&LocatableObject::GetDistance);
	lua::class_def<LocatableObject>(L, "GetDistance2D2obj",
		(float(LocatableObject::*)(const LocatableObject*) const)&LocatableObject::GetDistance2D);
	lua::class_def<LocatableObject>(L, "GetDistanceSq2obj",
		(float(LocatableObject::*)(const LocatableObject*) const)&LocatableObject::GetDistanceSq);
	lua::class_def<LocatableObject>(L, "GetDistance2DSq2obj",
		(float(LocatableObject::*)(const LocatableObject*) const)&LocatableObject::GetDistance2DSq);
	lua::class_def<LocatableObject>(L, "GetMapInstance", &LocatableObject::GetMapInstance);
	lua::class_def<LocatableObject>(L, "GetInstGuid", &LocatableObject::GetInstGuid);
	lua::class_def<LocatableObject>(L, "GetMapType", &LocatableObject::GetMapType);
	lua::class_def<LocatableObject>(L, "GetMapId", &LocatableObject::GetMapId);
	lua::class_def<LocatableObject>(L, "GetPosition", &LocatableObject::GetPosition);
	lua::class_def<LocatableObject>(L, "GetDirection", &LocatableObject::GetDirection);
	lua::class_def<LocatableObject>(L, "GetOrientation", &LocatableObject::GetOrientation);
	lua::class_def<LocatableObject>(L, "IsInWorld", &LocatableObject::IsInWorld);
	lua::class_def<LocatableObject>(L, "IstobeDisappear", &LocatableObject::IstobeDisappear);
	lua::class_def<LocatableObject>(L, "FastDisappear", &LocatableObject::FastDisappear);
	lua::class_def<LocatableObject>(L, "AttachObjectHookInfo", &LocatableObject::AttachObjectHookInfo);
	lua::class_def<LocatableObject>(L, "DetachObjectHookInfo", &LocatableObject::DetachObjectHookInfo);
	lua::class_def<LocatableObject>(L, "GetVariables", &LocatableObject::GetVariables);

	lua::class_add<StaticObject>(L, "StaticObject");
	lua::class_inh<StaticObject, LocatableObject>(L);
	lua::class_def<StaticObject>(L, "GetSpawnId", &StaticObject::GetSpawnId);
	lua::class_def<StaticObject>(L, "GetName", &StaticObject::GetName);
	lua::class_def<StaticObject>(L, "GetEntry", &StaticObject::GetEntry);
	lua::class_def<StaticObject>(L, "GetProto", &StaticObject::GetProto);

	lua::class_add<AuraObject>(L, "AuraObject");
	lua::class_inh<AuraObject, LocatableObject>(L);
	lua::class_def<AuraObject>(L, "ParseAuraPrototype", &AuraObject::ParseAuraPrototype);

	lua::class_add<Unit>(L, "Unit");
	lua::class_inh<Unit, LocatableObject>(L);
	lua::class_def<Unit>(L, "GetName", &Unit::GetName);
	lua::class_def<Unit>(L, "GetEntry", &Unit::GetEntry);
	lua::class_def<Unit>(L, "GetProto", &Unit::GetProto);
	lua::class_def<Unit>(L, "GetPlayerOwner", &Unit::GetPlayerOwner);
	lua::class_def<Unit>(L, "ForceMotionless", &Unit::ForceMotionless);
	lua::class_def<Unit>(L, "GetMoveSpeed", &Unit::GetMoveSpeed);
	lua::class_def<Unit>(L, "GetTurnSpeed", &Unit::GetTurnSpeed);
	lua::class_def<Unit>(L, "ModMoveSpeedInc", &Unit::ModMoveSpeedInc);
	lua::class_def<Unit>(L, "ModTurnSpeedInc", &Unit::ModTurnSpeedInc);
	lua::class_def<Unit>(L, "SetMoveMode", &Unit::SetMoveMode);
	lua::class_def<Unit>(L, "GetAttribute", &Unit::GetAttribute);
	lua::class_def<Unit>(L, "GetLevel", &Unit::GetLevel);
	lua::class_def<Unit>(L, "IsFriend", &Unit::IsFriend);
	lua::class_def<Unit>(L, "IsHostile", &Unit::IsHostile);
	lua::class_def<Unit>(L, "CanAttack", &Unit::CanAttack);
	lua::class_def<Unit>(L, "SetTeamSide", &Unit::SetTeamSide);
	lua::class_def<Unit>(L, "GetTeamSide", &Unit::GetTeamSide);
	lua::class_def<Unit>(L, "AttachOverlayAuraState", &Unit::AttachOverlayAuraState);
	lua::class_def<Unit>(L, "DetachOverlayAuraState", &Unit::DetachOverlayAuraState);
	lua::class_def<Unit>(L, "AddSysAuraState", &Unit::AddSysAuraState);
	lua::class_def<Unit>(L, "RemoveSysAuraState", &Unit::RemoveSysAuraState);
	lua::class_def<Unit>(L, "IsOutOfControl", &Unit::IsOutOfControl);
	lua::class_def<Unit>(L, "IsOutOfMove", &Unit::IsOutOfMove);
	lua::class_def<Unit>(L, "Strike", &Unit::Strike);
	lua::class_def<Unit>(L, "Hurt", &Unit::Hurt);
	lua::class_def<Unit>(L, "LoseHP", &Unit::LoseHP);
	lua::class_def<Unit>(L, "TreatHP", &Unit::TreatHP);
	lua::class_def<Unit>(L, "AddHPValue", &Unit::AddHPValue);
	lua::class_def<Unit>(L, "SubHPValue", &Unit::SubHPValue);
	lua::class_def<Unit>(L, "IsDead", &Unit::IsDead);
	lua::class_def<Unit>(L, "GetHPRate", &Unit::GetHPRate);
	lua::class_def<Unit>(L, "IsInCombat", &Unit::IsInCombat);
	lua::class_def<Unit>(L, "ResetToIdle", &Unit::ResetToIdle);
	lua::class_def<Unit>(L, "TryLockAttackObject", &Unit::TryLockAttackObject);
	lua::class_def<Unit>(L, "MoveToPriorPosition", &Unit::MoveToPriorPosition);
	lua::class_def<Unit>(L, "MoveToCombatPosition", &Unit::MoveToCombatPosition);
	lua::class_def<Unit>(L, "MoveToTarget", &Unit::MoveToTarget);
	lua::class_def<Unit>(L, "MoveToPosition", &Unit::MoveToPosition);
	lua::class_def<Unit>(L, "CancelPlanMove", &Unit::CancelPlanMove);
	lua::class_def<Unit>(L, "StopMove", &Unit::StopMove);
	lua::class_def<Unit>(L, "SetPriorMove", &Unit::SetPriorMove);
	lua::class_def<Unit>(L, "IsMoving", &Unit::IsMoving);
	lua::class_def<Unit>(L, "IsPriorMove", &Unit::IsPriorMove);
	lua::class_def<Unit>(L, "StartTurn", &Unit::StartTurn);
	lua::class_def<Unit>(L, "StopTurn", &Unit::StopTurn);
	lua::class_def<Unit>(L, "IsTurning", &Unit::IsTurning);
	lua::class_def<Unit>(L, "LearnSpell", &Unit::LearnSpell);
	lua::class_def<Unit>(L, "ForgetSpell", &Unit::ForgetSpell);
	lua::class_def<Unit>(L, "CanCastWithoutLearnSpell2Target", &Unit::CanCastWithoutLearnSpell2Target);
	lua::class_def<Unit>(L, "CanCastWithoutLearnSpell", &Unit::CanCastWithoutLearnSpell);
	lua::class_def<Unit>(L, "CastWithoutLearnSpell2Target", &Unit::CastWithoutLearnSpell2Target);
	lua::class_def<Unit>(L, "CastWithoutLearnSpell", &Unit::CastWithoutLearnSpell);
	lua::class_def<Unit>(L, "CanCastSpell2Target", &Unit::CanCastSpell2Target);
	lua::class_def<Unit>(L, "CanCastSpell", &Unit::CanCastSpell);
	lua::class_def<Unit>(L, "CastSpell2Target", &Unit::CastSpell2Target);
	lua::class_def<Unit>(L, "CastSpell", (GErrorCode(Unit::*)
		(uint32, uint64, const vector3f&, const std::string_view&))&Unit::CastSpell);
	lua::class_def<Unit>(L, "IsSpellCasting", &Unit::IsSpellCasting);
	lua::class_def<Unit>(L, "AttachSpellBuffInfo", &Unit::AttachSpellBuffInfo);
	lua::class_def<Unit>(L, "DetachSpellBuffInfo", &Unit::DetachSpellBuffInfo);

	lua::class_add<Creature>(L, "Creature");
	lua::class_inh<Creature, Unit>(L);
	lua::class_def<Creature>(L, "GetSpawnId", &Creature::GetSpawnId);
	lua::class_def<Creature>(L, "CanIdlePatrol", &Creature::CanIdlePatrol);
	lua::class_def<Creature>(L, "UpdateIdlePatrol", &Creature::UpdateIdlePatrol);

	lua::class_add<Player>(L, "Player");
	lua::class_inh<Player, Unit>(L);
	lua::class_def<Player>(L, "GetGuildId", &Player::GetGuildId);
	lua::class_def<Player>(L, "GetGuildTitle", &Player::GetGuildTitle);
	lua::class_def<Player>(L, "GetGuildName", &Player::GetGuildName);
	lua::class_def<Player>(L, "GetItemStorage", &Player::GetItemStorage);
	lua::class_def<Player>(L, "GetQuestStorage", &Player::GetQuestStorage);
	lua::class_def<Player>(L, "TeleportBy", &Player::TeleportBy);
	lua::class_def<Player>(L, "IsTeleporting", &Player::IsTeleporting);
	lua::class_def<Player>(L, "IsInTeam", &Player::IsInTeam);
	lua::class_def<Player>(L, "IsTeamMember", &Player::IsTeamMember);
	lua::class_def<Player>(L, "IsPlayTeamMember", &Player::IsPlayTeamMember);
	lua::class_def<Player>(L, "GetTeamId", &Player::GetTeamId);
	lua::class_def<Player>(L, "GetTeamName", &Player::GetTeamName);
	lua::class_def<Player>(L, "SaveConvoyStatus", &Player::SaveConvoyStatus);
	lua::class_def<Player>(L, "RemoveConvoyStatus", &Player::RemoveConvoyStatus);
	lua::class_def<Player>(L, "SendPacket",
		(void(Player::*)(uint32, const std::string_view&))&Player::SendPacket);
	lua::class_def<Player>(L, "SendPlayTips", &Player::SendPlayTips);
	lua::class_def<Player>(L, "PackClientAddr4Cross", &Player::PackClientAddr4Cross);

	lua::class_add<SObjPrototype>(L, "SObjPrototype");
	lua::class_mem<SObjPrototype>(L, "teleportPointID", &SObjPrototype::teleportPointID);
	lua::class_mem<SObjPrototype>(L, "teleportDelayTime", &SObjPrototype::teleportDelayTime);
}

static void InitLuaMap(lua_State* L)
{
	LuaTable t(L, "PlayerStorageFlag");
	t.set("INCLUDE_PLAYER", PSF_INCLUDE_PLAYER);
	t.set("INCLUDE_STRAY_PLAYER", PSF_INCLUDE_STRAY_PLAYER);
	t.set("INCLUDE_AUTO_PLAYER", PSF_INCLUDE_AUTO_PLAYER);
	t.set("EXCLUDE_PLAYER", PSF_EXCLUDE_PLAYER);
	t.set("EXCLUDE_STRAY_PLAYER", PSF_EXCLUDE_STRAY_PLAYER);
	t.set("EXCLUDE_AUTO_PLAYER", PSF_EXCLUDE_AUTO_PLAYER);

	t.reset(L, "MapHookEvent");
	t.set("OnPlayerPendingEnter", MapHookEvent::OnPlayerPendingEnter);
	t.set("OnPlayerLeaveMap", MapHookEvent::OnPlayerLeaveMap);
	t.set("OnPlayerEnter", MapHookEvent::OnPlayerEnter);
	t.set("OnPlayerLeave", MapHookEvent::OnPlayerLeave);
	t.set("OnCreatureSpawn", MapHookEvent::OnCreatureSpawn);
	t.set("OnStaticObjectSpawn", MapHookEvent::OnStaticObjectSpawn);
	t.set("OnUnitHurted", MapHookEvent::OnUnitHurted);
	t.set("OnUnitKilled", MapHookEvent::OnUnitKilled);
	t.set("OnUnitDead", MapHookEvent::OnUnitDead);
	t.set("OnSendMessage", MapHookEvent::OnSendMessage);
	t.set("OnHookDetach", MapHookEvent::OnHookDetach);

	lua::class_add<vector3f>(L, "vector3f");
	lua::class_con<vector3f>(L, lua::constructor<vector3f>);
	lua::class_mem<vector3f>(L, "x", &vector3f::x);
	lua::class_mem<vector3f>(L, "y", &vector3f::y);
	lua::class_mem<vector3f>(L, "z", &vector3f::z);

	lua::class_add<MapInstance>(L, "MapInstance");
	lua::class_cast<MapInstance, WheelRoutineType>(L);
	lua::class_cast<MapInstance, WheelTimerOwner>(L);
	lua::class_def<MapInstance>(L, "getMapId", &MapInstance::getMapId);
	lua::class_def<MapInstance>(L, "getMapType", &MapInstance::getMapType);
	lua::class_def<MapInstance>(L, "getInstGuid", &MapInstance::getInstGuid);
	lua::class_def<MapInstance>(L, "getOwnerGuid", &MapInstance::getOwnerGuid);
	lua::class_def<MapInstance>(L, "getOwnerGsId", &MapInstance::getOwnerGsId);
	lua::class_def<MapInstance>(L, "getOwnerGuidLow", &MapInstance::getOwnerGuidLow);
	lua::class_def<MapInstance>(L, "GetMostPossiblePlayerCount", &MapInstance::GetMostPossiblePlayerCount);
	lua::class_def<MapInstance>(L, "GetAutoPlayer", &MapInstance::GetAutoPlayer);
	lua::class_def<MapInstance>(L, "GetAvailablePlayer", &MapInstance::GetAvailablePlayer);
	lua::class_def<MapInstance>(L, "GetStrayPlayer", &MapInstance::GetStrayPlayer);
	lua::class_def<MapInstance>(L, "GetPlayer", &MapInstance::GetPlayer);
	lua::class_def<MapInstance>(L, "GetCreature", &MapInstance::GetCreature);
	lua::class_def<MapInstance>(L, "GetCreatureByEntry", &MapInstance::GetCreatureByEntry);
	lua::class_def<MapInstance>(L, "GetStaticObject", &MapInstance::GetStaticObject);
	lua::class_def<MapInstance>(L, "GetStaticObjectByEntry", &MapInstance::GetStaticObjectByEntry);
	lua::class_def<MapInstance>(L, "GetAuraObject", &MapInstance::GetAuraObject);
	lua::class_def<MapInstance>(L, "GetUnit", &MapInstance::GetUnit);
	lua::class_def<MapInstance>(L, "GetLocatableObject", &MapInstance::GetLocatableObject);
	lua::class_def<MapInstance>(L, "ForcePlayerLeave", &MapInstance::ForcePlayerLeave);
	lua::class_def<MapInstance>(L, "PlayGameOver", &MapInstance::PlayGameOver);
	lua::class_def<MapInstance>(L, "AddEvent", (void (MapInstance::*)(LuaRef&&))&MapInstance::AddEvent);
	lua::class_def<MapInstance>(L, "DeployCreature", &MapInstance::DeployCreature);
	lua::class_def<MapInstance>(L, "DeployStaticObject", &MapInstance::DeployStaticObject);
	lua::class_def<MapInstance>(L, "DeployStageCreature", &MapInstance::DeployStageCreature);
	lua::class_def<MapInstance>(L, "DeployStageStaticObject", &MapInstance::DeployStageStaticObject);
	lua::class_def<MapInstance>(L, "CleanupStageCreature", &MapInstance::CleanupStageCreature);
	lua::class_def<MapInstance>(L, "CleanupStageStaticObject", &MapInstance::CleanupStageStaticObject);
	lua::class_def<MapInstance>(L, "ClearAllHostileForcesCreature", &MapInstance::ClearAllHostileForcesCreature);
	lua::class_def<MapInstance>(L, "CreateCustomCreature", &MapInstance::CreateCustomCreature);
	lua::class_def<MapInstance>(L, "CreateCustomStaticObject", &MapInstance::CreateCustomStaticObject);
	lua::class_def<MapInstance>(L, "SpawnAuraObject", &MapInstance::SpawnAuraObject);
	lua::class_def<MapInstance>(L, "ForeachAllPlayer", &MapInstance::ForeachAllPlayer);
	lua::class_def<MapInstance>(L, "ForeachPlayer", &MapInstance::ForeachPlayer);
	lua::class_def<MapInstance>(L, "ForeachCreature", &MapInstance::ForeachCreature);
	lua::class_def<MapInstance>(L, "ForeachStaticObject", &MapInstance::ForeachStaticObject);
	lua::class_def<MapInstance>(L, "ForeachAuraObject", &MapInstance::ForeachAuraObject);
	lua::class_def<MapInstance>(L, "BroadcastPacket2AllPlayer", (void(MapInstance::*)
		(uint32, const std::string_view&)const)&MapInstance::BroadcastPacket2AllPlayer);
	lua::class_def<MapInstance>(L, "SendSysMsgToAll", &MapInstance::SendSysMsgToAll);
	lua::class_def<MapInstance>(L, "AttachMapHookInfo", &MapInstance::AttachMapHookInfo);
	lua::class_def<MapInstance>(L, "DetachMapHookInfo", &MapInstance::DetachMapHookInfo);
}

void InitLuaEnv(lua_State* L)
{
	InitLuaBase(L);
	InitLuaAttribute(L);
	InitLuaVariable(L);
	InitLuaItem(L);
	InitLuaQuest(L);
	InitLuaSpell(L);
	InitLuaObject(L);
	InitLuaMap(L);
}
